import _ from 'lodash'
import { ipcMain, Event } from 'electron'
import sqlite3 from 'sqlite3';
import IElectronModule from './bg_base';

/**
 * sql指令提交接口
 */
interface ISqlCommend {
    /** 数据库连接的关键字 */
    db_key: string,
    /** 语句 */
    statement: string,
    /** 参数 */
    params: Object | any[] | null
}

/**
 * sqlite 的操作工具
 */
class SqliteTool implements IElectronModule {

    private _database_map: Map<string, sqlite3.Database> = new Map<string, sqlite3.Database>();

    install(): void {
        ipcMain.on("sqlite-conn", this.connection.bind(this));
        ipcMain.on("sqlite-run", this.run.bind(this));
        ipcMain.on("sqlite-all", this.all.bind(this));
        ipcMain.on("sqlite-each", this.each.bind(this));
    }

    /**
     * 获取数据库连接并进行处理
     * @param key 数据库连接的关键字
     * @param event el事件对象
     * @param callback 获取到数据库连接后的处理方法
     */
    private get_db(key: string, event: Event, callback: (db: sqlite3.Database) => void): void {
        let db = this._database_map.get(key);
        if (!_.isNil(db)) {
            callback(db)
        }
        else {
            event.returnValue = {
                status: "error",
                message: "未连接数据库"
            };
        }
    }

    /**
     * 连接数据库
     * @param event 事件信息
     * @param param1.key 连接的识别关键字 
     */
    private connection(
        event: Event,
        { db_key = "", file = "" }: { db_key: string, file: string }
    ): void {
        db_key = _.isEmpty(db_key) ? "db_" + _.random(0, 99999) : db_key;
        let db = new sqlite3.Database(file, error => {
            this._database_map.set(db_key, db);
            event.returnValue = {
                status: error ? "error" : "success",
                message: error ? "数据库连接出错" : "数据库连接成功",
                error,
                db_key
            };
        });
    }

    /**
     * 数据库执行（无返回）
     * @param event  事件信息
     * @param param1 
     */
    private run(
        event: Event,
        { db_key = "", statement = "", params = null }: ISqlCommend
    ) {
        this.get_db(db_key, event, db => db.run(
            statement,
            _.isNil(params) ? [] : params,
            error => {
                event.returnValue = {
                    status: error ? "error" : "success",
                    message: error ? "执行出错" : "成功执行语句",
                    error
                };
            }
        ));
    }

    /**
     * 数据库查询
     * @param event  事件信息
     * @param param1 
     */
    private all(
        event: Event,
        { db_key = "", statement = "", params = null }: ISqlCommend
    ) {
        this.get_db(db_key, event, db => db.all(
            statement,
            _.isNil(params) ? [] : params,
            (error, rows) => {
                event.returnValue = {
                    status: error ? "error" : "success",
                    message: error ? "查询出错" : "成功获取数据",
                    error,
                    rows
                };
            }
        ));
    }

    /**
     * 数据库查询并且逐条获取数据
     * @param event 
     * @param param1 
     */
    private each(
        event: Event,
        { db_key = "", statement = "", params = null }: ISqlCommend
    ) {
        this.get_db(db_key, event, db => db.each(
            statement,
            _.isNil(params) ? [] : params,
            (error, row) => {
                event.sender.send("sqlite-each-row", {
                    status: error ? "error" : "success",
                    message: error ? "查询出错" : "成功获取一条数据",
                    error,
                    row
                });
            },
            (error, count) => {
                event.sender.send("sqlite-each-end", {
                    status: error ? "error" : "success",
                    message: error ? "查询出错" : "获取数据结束",
                    error,
                    count
                });
            }
        ));
    }

    /**
     * 关闭数据库
     * @param event 
     * @param param1 
     */
    private close(
        event: Event,
        { db_key = "" }: { db_key: string }
    ) {
        this.get_db(db_key, event, db => db.close(
            error => {
                event.returnValue = {
                    status: error ? "error" : "success",
                    message: error ? "" : "成功关闭连接",
                    error
                };
            }
        ));

    }
}

export default new SqliteTool();
